package cyber2d.core;

//java
import java.util.LinkedList;
//slick
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;
//phys2d
import net.phys2d.math.Vector2f;
import net.phys2d.raw.Body;
import net.phys2d.raw.BodyList;
import net.phys2d.raw.CollisionEvent;
import net.phys2d.raw.CollisionListener;
import net.phys2d.raw.StaticBody;
import net.phys2d.raw.World;
import net.phys2d.raw.shapes.Box;
import net.phys2d.raw.strategies.QuadSpaceStrategy;
//cyber2d
import cyber2d.core.objects.Creature;
import cyber2d.core.objects.GameEvent;
import cyber2d.core.objects.Shot;
import cyber2d.core.objects.Tile;
import cyber2d.core.objects.act.ActivatorFactory;

//this is level that currently executed
//all physycs should be included
public class PlatformerLevel implements CollisionListener
{
	//int levelSizeX, levelSizeY; //level size (in tiles)
	//int tileSizeX, tileSizeY; //size of 1 tile
	
	//Image backgroundLayer; //some city,cave or sky at he background
	
	//LinkedList<LevelObject> levelObjects;
	
	public World world; //container for physics and collisions
	public LinkedList <Shot> shotList; //store all shots
	public LinkedList <CollisionEvent> ceList; //list that sore collisions after each step
	public ActivatorFactory actFactory;
	public LinkedList <GameEvent> geList; //game events: new shots, etc 
	public LinkedList <Creature> creatureList; //list of creatures in current level
	
	public Creature player; //direct link to human controllable creature
	
	//temp
	SpriteSheet playerSprites;
	SpriteSheet enemySprites;
	SpriteSheet shotA;
	SpriteSheet shotAexp;
	
	public PlatformerLevel()
	{
		//create world
		world = new World(new Vector2f(0, 10), 10, new QuadSpaceStrategy(8,8));
		world.addListener(this);
		//for collision
		ceList = new LinkedList<CollisionEvent>();
		actFactory = new ActivatorFactory(world);
		
		//loading sprites
		try
		{
			enemySprites = new SpriteSheet("res/metA.png", 30, 60);
			playerSprites = new SpriteSheet("res/metB.png", 30, 60);
			shotA = new SpriteSheet("res/shotA.png", 3, 3);
			shotAexp = new SpriteSheet("res/shotAexp.png", 30, 30);
		} catch (SlickException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
			//add objects
		//add level borders
		Tile border1 = new Tile(world);
		border1.body = new StaticBody("border 1", new Box(2000, 10));
		border1.body.setPosition(0, -1000);
		border1.body.setUserData(border1);
		world.add(border1.body);
		
		Tile border2 = new Tile(world);
		border2.body = new StaticBody("border 2", new Box(10, 2000));
		border2.body.setPosition(1000, 0);
		border2.body.setUserData(border2);
		world.add(border2.body);
		
		Tile border3 = new Tile(world);
		border3.body = new StaticBody("border 3", new Box(2000, 10));
		border3.body.setPosition(0, 1000);
		border3.body.setUserData(border3);
		world.add(border3.body);
		
		Tile border4 = new Tile(world);
		border4.body = new StaticBody("border 4", new Box(10, 2000));
		border4.body.setPosition(-1000, 0);
		border4.body.setUserData(border4);
		world.add(border4.body);
		
		//add tiles
		Tile tile1 = new Tile(world);
		tile1.body = new StaticBody("platform 1", new Box(1800, 20));
		tile1.body.setUserData(tile1);
		tile1.body.setPosition(0, 900);
		world.add(tile1.body);
		
		Tile tile2 = new Tile(world);
		tile2.body = new StaticBody("wall 2", new Box(200, 20));
		tile2.body.setUserData(tile2);
		tile2.body.setPosition(100, 700);
		world.add(tile2.body);
		
		Tile tile3 = new Tile(world);
		tile3.body = new StaticBody("wall 1", new Box(20, 200));
		tile3.body.setUserData(tile3);
		tile3.body.setPosition(200, 700);
		world.add(tile3.body);
		
		/*//add objects
		Body body8 = new Body("Box1", new Box(40, 40), 300);
		body8.setPosition(210, -120);
		world.add(body8);*/
		
			//add creatures
		creatureList = new LinkedList<Creature>();
		
		//add player
		player = new Creature(world, this, playerSprites); //create
		player.hpMax = 100;
		player.hpCur = 100;
		player.name = "player";
		player.body = new Body("player", new Box(30, 60), 100); //create body for it
		player.body.setUserData(player); //create back reference
		player.body.setPosition(80, 520); //set position
		player.body.setRotatable(false); //body will not rotate
		world.add(player.body); //add body to world
		creatureList.add(player); //add creature to list
		
		//add enemy
		Creature enemy = new Creature(world, this, enemySprites);
		enemy.hpMax = 170;
		enemy.hpCur = 170;
		enemy.name = "enemy 1";
		enemy.body = new Body("enemy 1", new Box (30,60), 70);
		enemy.body.setUserData(enemy);
		enemy.body.setPosition(400, 550);
		enemy.body.setRotatable(false);
		world.add(enemy.body);
		creatureList.add(enemy);
		
		//System.out.println(player.body.getShape().getBounds());
		
			//fill shot types
		//create list
		shotList = new LinkedList<Shot>();
		//add shot
		Body b = new Body("shot", new Box(5,5), 5); //size 5*5, mass 5
		b.setGravityEffected(false); //set not affected by gravity
		Shot s = new Shot(world, "9mm", "standart ammo", b, 50, 15000, shotA); //dmg 50, force 10000
		shotList.add(s); //add shot to list
		b.setUserData(s); //link it with shot
		
	}
	
	public void render(Graphics g)
	{		
		//define position to draw
		float offsetX = 0;
		float offsetY = 0;
		
		//change offcet according to player position
		offsetX = player.body.getPosition().getX()-300;
		offsetY = player.body.getPosition().getY()-200;
		
		//define objects to draw
		BodyList bodies = world.getBodies();
			
		//draw background
		
		//draw back decor
		
			//draw tiles and objects
		//creatures
		for (Creature creature: creatureList)
		{
			if (creature.getImage() != null) //if object have image
			{
				g.drawImage(creature.getImage(),
						creature.body.getPosition().getX()-15-offsetX,
						creature.body.getPosition().getY()-30-offsetY);
			}
		}
		//shots
		for (Shot shot: shotList)
		{
			if (shot.getImage() != null) //if object have image
			{
				g.drawImage(shot.getImage(),
						shot.body.getPosition().getX()-1-offsetX,
						shot.body.getPosition().getY()-1-offsetY);
			}
		}
		
		
		//rectangles
		for (int i=0;i<bodies.size();i++) {
			Body body = (Body) bodies.get(i);
			Box box = (Box) body.getShape();
			Vector2f[] pts = box.getPoints(body.getPosition(), body.getRotation());
			
			Vector2f v1 = pts[0];
			Vector2f v2 = pts[1];
			Vector2f v3 = pts[2];
			Vector2f v4 = pts[3];
			
			g.setColor(Color.black);
			g.drawLine((int) v1.x-offsetX,(int) v1.y-offsetY,(int) v2.x-offsetX,(int) v2.y-offsetY);
			g.drawLine((int) v2.x-offsetX,(int) v2.y-offsetY,(int) v3.x-offsetX,(int) v3.y-offsetY);
			g.drawLine((int) v3.x-offsetX,(int) v3.y-offsetY,(int) v4.x-offsetX,(int) v4.y-offsetY);
			g.drawLine((int) v4.x-offsetX,(int) v4.y-offsetY,(int) v1.x-offsetX,(int) v1.y-offsetY);
		}
		//draw effects
		
		//draw front decor
		
		//draw gui

	}
	
	public void update()
	{
		//events
		/*for(GameEvent gameEvent: geList)
		{
			
		}*/
		
		//execute controls (add forces), add new shots
		
		//creatures
		for(Creature creature: creatureList)
		{
			//if creature has HP below zero
			if (creature.hpCur < 0)
			{
				creature.dead = true; //set it as dead
			}
			//else update it
			else
			{
				creature.update();
			}
			//System.out.println(creature.name + " " + creature.hpCur);
		}		
		
		//remove dead creatures
		int clSize = creatureList.size();
		for (int i = 0; i < clSize; i++)
		{
			Creature creature = creatureList.get(i);
			if (creature.dead)
			{
				//remove from level
				//remove body
				world.remove(creature.body);
				//remove object
				creatureList.remove(creature);
				
				//fix list size and iterator
				clSize -= 1;
				i -= 1;
			}
		}
		
		//proceed world
		world.step();
		
		//process collision events
		for(CollisionEvent ce: ceList)
		{
			actFactory.createActivator(ce);
		}
		//clear collision list
		ceList.clear();
	}

	public void collisionOccured(CollisionEvent event)
	{
		ceList.add(event);
		//System.out.println(event.getBodyA().toString() + "   " + event.getBodyB().toString());
		
	}

	
	public Creature getPlayer()
	{
		return null;
	}
	
	/**method that add shots to world
	 * 
	 * @param name
	 * @param x - x coordinate of starting position
	 * @param y - y coordinate of starting position
	 * @param direction - direction where shot will move
	 */
	public void addShot(String name, float x, float y, int direction)
	{
		for (Shot shot: shotList)
		{
			if (shot.name == name)
			{
				//create ne body for shot
				Body b = shot.getBodyCopy();
				//Body b = (Body) shot.body.clone(); //copy from template
				//set coordinates
				b.setPosition(x-shot.body.getShape().getBounds().getWidth()*direction, y);
				//add it to world
				world.add(b);
				//add forces/speed to body
				b.addForce(new Vector2f(direction*shot.force, 0));
			}
		}
	}
}
